//
//  SimpleXMLParser.cpp
//  sad
//
//  Created by Christopher Kemsley on 2/2/12.
//  Copyright (c) 2012 iAppolopolis. All rights reserved.
//


#include <fstream>
#include "XMLParser.hpp"
#include "Log.hpp"
#include "FileIO.hpp"

using namespace Sim ;






bool	XMLParser :: parse	( URL const & path , Any & XMLParser )
	{
	std::string		file ;
	
	file = FileIO :: contentsOfURL ( path ) ;
	
	if ( file.size() != 0 )
		{
		return ( 0 != parse ( file , XMLParser ) ) ;
		}
	
	return false ;
	}




XMLParser::Offset	XMLParsingAgent :: offsetToOpenTag		( std::string const & string , XMLParser::Offset start )
	{
	return string . find ( openTag , start ) ;
	}
std::vector<XMLParsingAgent*>&	XMLParsingAgent :: agents ()
	{
	static std::vector<XMLParsingAgent*> s ; return s ;
	}
XMLParsingAgent :: XMLParsingAgent ( std::string const & name )
:	openTag		( "<" + name + ">" )
	{
	agents() . push_back ( this ) ;
	}



/*
 Given "<string>test</string>"
 
 This will:
 
 - Find the position of the tag opener (with 'start' offset)
 - If this is after the 'stop' position, return 0
 - Add the opener length to the position
 - Call the closest agent's 'parse' method
 - Return the openTag size plus the returned size
 */
XMLParser::Offset	XMLParser :: parse	( std::string const & file , Any & XMLParser , XMLParser::Offset start )
	{
	std::vector<XMLParsingAgent*>::iterator	here	=	XMLParsingAgent::agents().begin () ;
	std::vector<XMLParsingAgent*>::iterator	end		=	XMLParsingAgent::agents().end () ;
	
	XMLParsingAgent*	closest		=	0 ;
	XMLParser::Offset	position	=	std::string::npos ;
	
	// Go through the agents
	while ( here < end )
		{
		XMLParsingAgent*	agent	=	*(here++) ;
		
		XMLParser::Offset	p			=	agent -> offsetToOpenTag ( file , start ) ;
		
		Log::states("XMLParser") << "...Parser... offset to " << agent->openTag << " = " << p ;
		
		// If it's closer than the last one...
		if ( p < position )
			{
			closest = agent ;
			position = p ;
			}
		}
	
	// If we found one close enough
	if ( position < std::string::npos )
		{
		XMLParser::Offset openTagSize = (closest->openTag).size() ;
		position += openTagSize ; // skip to end of open tag
		
		position = closest -> parse ( file , XMLParser , position ) ;
		if ( position == 0 )	// we didn't find anything
			return 0 ;
		return position ;
		}
	
	return 0 ;
	}




bool	XMLParser :: get		( Any const & XMLParser , std::string const & keyPath , Any & outValue )
	{
	XMLParser::Offset				start	=	0 ;
	XMLParser::Offset				end ;
	static std::string	period	( "." ) ;
	std::vector<std::string>	path ;
	
	while ( std::string::npos != (end=keyPath.find(period,start)) )
		{
		path . push_back ( keyPath.substr(start,end-start) ) ;
		start = end ;
		}
	keyPath.substr(start) ;
	
	//return traverse ( XMLParser , path , 0 , outValue ) ;
	return 0 ;
	}






XMLParser::Offset	XMLParserHelper :: findNextClose			( std::string const& file , XMLParser::Offset start , XMLParser::Offset & close/*or npos*/ )
	{
	static std::string	closeTag	( "</" ) ;
	
	close	=	file . find ( closeTag , start ) ;
	
	return close - start ;
	}
XMLParser::Offset	XMLParserHelper :: findNextOpenClosePair	( std::string const& file , XMLParser::Offset start , XMLParser::Offset & open/*or npos*/ , XMLParser::Offset & close/*or npos*/ )
	{
	static std::string	openTag		( "<" ) ;
	static std::string	closeTag	( "</" ) ;
	
	open	=	file . find ( openTag , start ) ;
	close	=	file . find ( closeTag , start ) ;
	
	return close - open ;
	}
XMLParser::Offset	XMLParserHelper :: getImmediateString		( std::string const& file , XMLParser::Offset start , std::string & value )
	{
	XMLParser::Offset	lengthO	;
	XMLParser::Offset	length		=	XMLParserHelper :: findNextClose ( file , start , lengthO ) ;
	
	if ( length == std::string::npos )	return 0 ;
	
	value = file.substr ( start , length ) ;
	
	return length ;
	}












